<?php


namespace app\webactive\controller;


use app\common\cachemodel\UserCoupon;
use app\common\cachemodel\ZlActivePrizeNumIncRecord;
use app\common\cachemodel\ZlActivePrizeRecord;
use app\common\cachemodel\ZlActivePrizrUserInfo;
use app\common\lib\exception\ApiException;
use app\common\lib\Util;
use app\webactive\service\Prize;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Env;
use think\exception\DbException;
use think\Log;
use think\response\Json;
use XznsTools\cache\CacheManage;
use \Exception;

class Active extends Auth
{
    protected $isTest = false;
    protected $noLoginActions = ['shareindex', 'prizerecords'];

    public $activeId = 0;
    public $config;

    /**
     * @throws ApiException
     */
    public function _initialize()
    {
        parent::_initialize();
        $this->config = config('boxactive');

        $this->activeId = input('active_id/d', 0);
        if (!$this->activeId || !isset($this->config[$this->activeId]))
        {
            throw new ApiException('活动异常，请稍后再试～', 200, config('code.error'));
        }

        $this->assign('oss', Env::get('host.photo'));
        $this->assign('domain', Env::get('host.domain'));
    }

    /**
     * 活动首页
     * @return mixed
     * @throws Exception
     */
    public function index()
    {
        if ($this->isTest)
        {
            $headers = [
                'app-type' => 'android',
                'version' => '2.4.5',
                'did' => 'ffffffff-e8e4-223d-0000-0000448ab817',
                'access-token' => 'zY6yiDky8EVPp0WITOwn3KFoTC5irp18O99yQHISi706y0WUZp1I5EazPzBbNpSeegUw7KPDIRZqJmFgesp5ng==',
                'sign' => '/PKNJ+yuQtxfvm1pK9Uhu0F2VECpBIvrIjr5g74wmTtK/i107xeGv8Kgs9rbEMROTGhqBY6cHeAMbkOorgi5GaR5cMZnoOFHoIS/wcN9InT1qHM5llfhQGXo3ECeRURF1Tp1pxBbLy3AjGOTwplQUv7xCGph7dYHd/Tz1RDasrfOo32xQKeGYxpbT8ZnSt0h',
            ];
        } else
        {
            $headers = $this->request->header();
            $headers = [
                'app-type' => $headers['app-type'],
                'version' => $headers['version'],
                'did' => $headers['did'],
                'access-token' => $headers['access-token'],
                'sign' => $headers['sign'],
            ];
        }

        $time = $this->request->time();
        $date = (int)(date('Ymd'));

        $userTaskCompletionDetailsToday = (new ZlActivePrizeNumIncRecord())->getUserTaskCompletionDetailsToday($this->user['id'], $this->activeId, $date);

        $shareTypeInfo = [];

        foreach ($this->config[$this->activeId]['task']['list'] as $taskId => $taskItem)
        {
            $shareTypeInfo[] = [
                'num' => $userTaskCompletionDetailsToday[$taskId] ?? 0,
                'max_num' => $taskItem['max_num']
            ];
        }
        $activeStatus = 2;  // 活动进行中
        if ($time < $this->config[$this->activeId]['start_time'])
        {
            $activeStatus = 1; // 活动未开始
        }
        if ($time > $this->config[$this->activeId]['end_time'])
        {
            $activeStatus = 3; // 活动已结束
        }

        if ($activeStatus === 2)
        {   // 活动进行中 做每日进入任务
            (new ZlActivePrizeNumIncRecord())->userDoTheTask($this->user['id'], $this->activeId, 1);
        }

        $userPrizeInfoModel = new ZlActivePrizrUserInfo();
        $userPrizeInfo = $userPrizeInfoModel->getUserPrizeInfo($this->user['id'], $this->activeId);

        return $this->fetch($this->config[$this->activeId]['template'], [
                'shareTitle' => $this->config[$this->activeId]['share_title'],
                'description' => $this->config[$this->activeId]['description'],
                'user_prize_info' => [
                    'potential' => (int)$userPrizeInfo['potential'] >= 100 ? 100 : (int)$userPrizeInfo['potential'], // 能力值
                    'prize_unsuc_num' => (int)$userPrizeInfo['prize_unsuc_num'], // 可抽奖次数
                ],
                'status' => $activeStatus, // 活动状态 1=>活动未开始 2=>活动进行中 3=>活动已结束
                'app_type' => $headers['app-type'] ?? '',
                'active_id' => $this->activeId,
                'version' => Util::androidVersion('2.2.0'),
                'headers' => \GuzzleHttp\json_encode($headers, JSON_UNESCAPED_UNICODE),
                'headers_urlencode' => urlencode(\GuzzleHttp\json_encode($headers, JSON_UNESCAPED_UNICODE)),
                'share_type_info' => \GuzzleHttp\json_encode($shareTypeInfo)
            ]
        );
    }

    /**
     * 获取用户活动抽奖信息
     * @return Json
     * @throws Exception
     */
    public function getPrizeInfo()
    {
        $time = $this->request->time();
        $date = (int)(date('Ymd'));
        $userPrizeInfoModel = new ZlActivePrizrUserInfo();
        $userPrizeInfo = $userPrizeInfoModel->getUserPrizeInfo($this->user['id'], $this->activeId);

        $userTaskCompletionDetailsToday = (new ZlActivePrizeNumIncRecord())->getUserTaskCompletionDetailsToday($this->user['id'], $this->activeId, $date);

        $activeStatus = 2;  // 活动进行中
        if ($time < $this->config[$this->activeId]['start_time'])
        {
            $activeStatus = 1; // 活动未开始
        }
        if ($time > $this->config[$this->activeId]['end_time'])
        {
            $activeStatus = 3; // 活动已结束
        }

        $shareTypeInfo = [];
        foreach ($this->config[$this->activeId]['task']['list'] as $taskId => $taskItem)
        {
            $shareTypeInfo[] = [
                'num' => $userTaskCompletionDetailsToday[$taskId] ?? 0,
                'max_num' => $taskItem['max_num']
            ];
        }

        $data = [
            'potential' => (int)$userPrizeInfo['potential'] >= 100 ? 100 : (int)$userPrizeInfo['potential'], // 能力值
            'prize_unsuc_num' => (int)$userPrizeInfo['prize_unsuc_num'], // 可抽奖次数
            'status' => $activeStatus, // 活动状态 1=>活动未开始 2=>活动进行中 3=>活动已结束
            'share_type_info' => \GuzzleHttp\json_encode($shareTypeInfo)
        ];

        return show(200, '请求成功', $data);
    }


    /**
     * 分享首页
     */
    public function shareIndex()
    {
        $prizeRecords = $this->getPrizeRecords();

        return $this->fetch($this->config[$this->activeId]['template_share'], [
            'prizeReccord' => \GuzzleHttp\json_encode($prizeRecords, JSON_UNESCAPED_UNICODE)
        ]);
    }

    /**
     * 抽奖历史记录
     */
    public function prizeRecords()
    {
        $headers = input('headers/s', '');

        $headersArray = \GuzzleHttp\json_decode($headers, true);

        $appType = $headersArray['app-type'] ?? '';
        if ($appType === 'android')
        {
            $headers = json_encode($this->request->header(), true);
        }

        return $this->fetch($this->config[$this->activeId]['template_record'], [
            'app_type' => $appType,
            'headers' => $headers
        ]);
    }

    /**
     * 抽奖
     * @return Json
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws Exception
     */
    public function luckyDraw(): Json
    {
        $time = $this->request->time();
        if ($time < $this->config[$this->activeId]['start_time'])
        {
            return show(config('code.error'), '活动还未开始');
        }
        if ($time > $this->config[$this->activeId]['end_time'])
        {
            return show(config('code.error'), '活动已结束');
        }

        $userPrizeInfoModel = new ZlActivePrizrUserInfo();
        $activePrizeRecord = new ZlActivePrizeRecord();
        $userPrizeInfo = $userPrizeInfoModel->getUserPrizeInfo($this->user['id'], $this->activeId);

        if ($userPrizeInfo['prize_unsuc_num'] <= 0)
        {
            return show(config('code.error'), '暂已无抽奖次数');
        }
        $updateUserPrizeInfo = [];
        if ($userPrizeInfo['potential'] >= 100)
        {   // 进行高级抽奖
            if ($userPrizeInfo['senior_peize_num'] < 1)
            {   // 第一次抽奖
                $prizeId = 16; // 奖项ID
            } else
            {   // 第二次及以上
                $prizeId = 15;  // 奖项ID
            }
            $updateUserPrizeInfo['potential'] = $userPrizeInfo['potential'] - 100;
            $updateUserPrizeInfo['prize_unsuc_num'] = $userPrizeInfo['prize_unsuc_num'] - 1;
            $updateUserPrizeInfo['senior_peize_num'] = $userPrizeInfo['senior_peize_num'] + 1;
            $prizeType = 2;  // 抽奖类型 1=>普通抽奖 2=>高级抽奖
        } else
        {   // 普通抽奖
            $updateUserPrizeInfo['potential'] = $userPrizeInfo['potential'] + (random_int(30, 35) / 10); // 抽奖后能力值随机增长3%～3.5%
            if ($updateUserPrizeInfo['potential'] < 100)
            {   // 潜力值没有满时 消耗一次抽奖次数 如果潜力值满了 则会增加一次抽奖次数和当前抽次数抵消 不变 -1 +1 = 0
                $updateUserPrizeInfo['prize_unsuc_num'] = $userPrizeInfo['prize_unsuc_num'] - 1;
            } else
            {
                $updateUserPrizeInfo['total_prize_num'] = $userPrizeInfo['total_prize_num'] + 1;
            }
            // 当前是第几次抽奖
            $updateUserPrizeInfo['prize_lucky_num'] = $userPrizeInfo['prize_lucky_num'] + 1;

            if (isset($this->config[$this->activeId]['prize_num_must_lucky'][$updateUserPrizeInfo['prize_lucky_num']]))
            {   // 当前抽奖次数必中
                $prizeId = $this->config[$this->activeId]['prize_num_must_lucky'][$updateUserPrizeInfo['prize_lucky_num']];
            } else
            {   // 正常抽奖
                $prizeProbability = $this->config[$this->activeId]['prize']; // 奖品中奖概率
                // 获取个人普通抽奖奖品统计
                $userPrizeCount = $activePrizeRecord->getUserPrizerNumCount($this->user['id'], $this->activeId);
                foreach ($userPrizeCount as $prizeIdItem => $prizeIdCountNum)
                {
                    if (isset($this->config[$this->activeId]['prize_info'][$prizeIdItem]['max_num'])
                        && $this->config[$this->activeId]['prize_info'][$prizeIdItem]['max_num'] > 0
                        && $prizeIdCountNum >= $this->config[$this->activeId]['prize_info'][$prizeIdItem]['max_num'])
                    {
                        unset($prizeProbability[$prizeIdItem]); // 过滤到达个人领取数量上线的奖品
                    }
                }
                // 或者总共奖品发放数量
                $allPrizeCount = $activePrizeRecord->getPrizerNumCount($this->activeId);
                foreach ($allPrizeCount as $prizeIdItem1 => $allPrizeIdCountNum)
                {
                    if (isset($this->config[$this->activeId]['prize_info'][$prizeIdItem1]['max_num'])
                        && $this->config[$this->activeId]['prize_info'][$prizeIdItem1]['max_num'] > 0
                        && $allPrizeIdCountNum >= $this->config[$this->activeId]['prize_info'][$prizeIdItem1]['max_num'])
                    {
                        unset($prizeProbability[$prizeIdItem1]); // 过滤总共到达发放数量上线的奖品
                    }
                }

                $prizeModel = new Prize();
                do
                {
                    // 抽奖
                    $prizeId = $prizeModel->setPrizeProbability($prizeProbability)->getPrizeId();
                    $prizeStatus = $activePrizeRecord->prizerNumCountInc($this->user['id'], $this->activeId, $prizeId, $this->config[$this->activeId]['prize_info'][$prizeId]['total_max_num'] ?? 0); // 中奖奖品是否有效；并更新奖品发放数量 true有效  false无效
                    unset($prizeProbability[$prizeId]); // 去除奖项
                } while (!$prizeStatus);
            }
            $prizeType = 1; // 抽奖类型 1=>普通抽奖 2=>高级抽奖
        }

        // 获取抽奖结果 优惠券
        $resPrizeCouponData = $this->config[$this->activeId]['prize_info'][$prizeId]['cid'][array_rand($this->config[$this->activeId]['prize_info'][$prizeId]['cid'], 1)];
        // 更新用户抽奖信息
        $res = $userPrizeInfoModel->updateData($this->user['id'], $this->activeId, $updateUserPrizeInfo, (int)$userPrizeInfo['id']);
        if (!$res)
        {
            return show(config('code.error'), '服务异常，请稍后再试～');
        }
        $boxAttr = array_rand($this->config[$this->activeId]['flags']);
        // 给用户发放抽奖优惠券
        if ($resPrizeCouponData['cid'])
        {   // 不是谢谢回顾 则发放优惠券
            $couponInfo = Db::table('wechat_backup_07_18_14_43_00.zl_coupon_attr')->where('id', $resPrizeCouponData['cid'])->field('desc,type,discount,rand_min,rand_max,ur_id')->find();
            $prizeName = $couponInfo['desc'];
            $price = (int)$couponInfo['type'] === 4 ? random_int($couponInfo['rand_min'], $couponInfo['rand_max']) : 0;
            $cData = [
                'uid' => $this->user['id'],
                'c_id' => $resPrizeCouponData['cid'],
                'ur_id' => $couponInfo['ur_id'],
                'start_time' => $time,
                'end_time' => strtotime("+{$resPrizeCouponData['duration']} day"),
                'give_time' => $time,
                'status' => 0,
                'price' => $price,
                'is_give' => $resPrizeCouponData['is_give'],
                'create_time' => $time,
                'update_time' => 0
            ];
            $cid = (new UserCoupon())->insertGetId($cData);
            CacheManage::getInstance()->setCacheConfig('user.coupon', $this->user['id'])->listAdd([$cid => $cid], 1); // 未使用
            if ($resPrizeCouponData['is_give'])
            {   // 可增与
                CacheManage::getInstance()->setCacheConfig('user.coupon', $this->user['id'])->listAdd([$cid => $cid], 2); // 可增与
            }

            if ($prizeType === 2 || $updateUserPrizeInfo['prize_lucky_num'] < 6 || $updateUserPrizeInfo['prize_lucky_num'] % 3 === 0)
            {   // 记录轮播 中奖记录
                $this->prizeRecordCacheAdd($this->activeId, $boxAttr, $prizeName);
            }
        } else
        {
            $prizeName = $resPrizeCouponData['prize_name'];
            $cid = 0;
        }
        // 写入抽奖记录
        $prizeRecordData = [
            'uid' => $this->user['id'],
            'active_id' => $this->activeId,
            'attr' => $boxAttr,
            'cid' => $cid,
            'prize_name' => $prizeName,
            'prize_id' => $prizeId,
            'prize_type' => $prizeType,
            'create_time' => $this->request->time()
        ];
        $activePrizeRecord->saveData($this->user['id'], $this->activeId, $prizeRecordData);

        $resData = [
            'potential' => (int)($updateUserPrizeInfo['potential'] >= 100 ? 100 : $updateUserPrizeInfo['potential']), // 潜力值
            'prize_unsuc_num' => $updateUserPrizeInfo['prize_unsuc_num'] ?? (int)$userPrizeInfo['prize_unsuc_num'], // 剩余抽奖次数
            'prize_type' => $prizeType, // 抽奖类型 1=>普通抽奖 2=>高级抽奖
            'box_name' => $this->config[$this->activeId]['flags'][$prizeRecordData['attr']], //  盲盒属性
            'is_empty' => $cid === 0 ? 1 : 0,
            'prize_name' => $prizeName, // 奖品名字
            'prize_name_desc' => $resPrizeCouponData['prize_name']
        ];

        if ($cid === 0)
        {
            $msg = "不小心抽到空盒啦\r\n试试下一个吧！";
        } else
        {
            $msg = "恭喜您抽中{$this->config[$this->activeId]['flags'][$boxAttr]}！\r\n获得一张{$prizeName}！";
        }

        return show(config('code.success'), $msg, $resData);
    }

    /**
     * 每日任务
     * @return Json
     * @throws Exception
     */
    public function task(): Json
    {
        $taskId = input('task_id/d', 0);
        if (!$taskId || !in_array($taskId, [2, 3, 4, 5], true))
        {
            return show(config('code.error'), '请求异常，请稍后再试～');
        }

        $time = $this->request->time();
        if ($time < $this->config[$this->activeId]['start_time'])
        {
            return show(config('code.error'), '活动还未开始');
        }
        if ($time > $this->config[$this->activeId]['end_time'])
        {
            return show(config('code.error'), '活动已结束');
        }

        $taskRes = (new ZlActivePrizeNumIncRecord())->userDoTheTask($this->user['id'], $this->activeId, $taskId);

        return show(200, '请求成功', $taskRes);
    }

    /**
     * 获取抽奖记录
     * @return Json
     * @throws Exception
     */
    public function getPrizeRecordList(): Json
    {
        $resData = (new ZlActivePrizeRecord())->getRecordList($this->user['id'], $this->activeId);

        return show(200, '请求成功', $resData);
    }

    /**
     * 记录抽奖记录 用于页面轮播滚动
     * @param int $activeId
     * @param int $boxAttr
     * @param string $prizeName
     */
    private function prizeRecordCacheAdd(int $activeId, int $boxAttr, string $prizeName): void
    {
        $len = 15;
        // 获取redis操作对象
        $redis = CacheManage::getInstance()->redisHandler;

        $cacheKey = 'prize_active:prize:record:' . $activeId;
        $num = $redis->lLen($cacheKey);

        if ($num >= $len)
        {
            $redis->rPop($cacheKey);
        }

        $info = [
            'nickname' => $this->user['nickname'],
            'flag' => $boxAttr,
            'prize_name' => $prizeName,
        ];

        $record = \GuzzleHttp\json_encode($info);

        $redis->lPush($cacheKey, $record);
    }

    private function getPrizeRecords(): array
    {
        $redis = CacheManage::getInstance()->redisHandler;

        $giveData = $redis->lRange('prize_active:prize:record:' . $this->activeId, 0, -1);

        $giveData = $giveData ?: [];

        $data = [];
        foreach ($giveData as $value)
        {
            $d = \GuzzleHttp\json_decode($value, true);

            if ($d['nickname'])
            {
                $data[] = [
                    'nickname' => $d['nickname'],
                    'box_name' => $this->config[$this->activeId]['flags'][$d['flag']],
                    'prize_name' => $d['prize_name']
                ];
            }
        }

        return $data;
    }

    /**
     * 获取统计结果数据
     * @throws DbException
     */
    public function getStatisticalData(): void
    {
        $prizeUserInfoModel = new ZlActivePrizrUserInfo();

        $userDatas = $prizeUserInfoModel->where('active_id', $this->activeId)->field('count(*) user_num,sum(prize_unsuc_num) prize_unsuc_num,sum(total_prize_num) total_prize_num,sum(senior_peize_num) senior_peize_num,sum(prize_lucky_num) prize_lucky_num')->find();
        print_r(date('Y-m-d H:i:s') . " 元旦活动数据统计\r\n");

        printf("参与活动用户：%d 剩余为抽奖次数：%d 普通抽奖次数：%d 潜力值抽奖次数：%d 总共抽奖次数：%d 用户平均抽奖次数：%.1f次 \n", $userDatas['user_num'], $userDatas['prize_unsuc_num'], $userDatas['prize_lucky_num'], $userDatas['senior_peize_num'], $userDatas['total_prize_num'], $userDatas['total_prize_num'] / $userDatas['user_num']);

        $prizeRecordModel = new ZlActivePrizeRecord();

        $prizeNameConfig = [
            1 => '谢谢参与',
            2 => '9.5折券',
            3 => '9折券',
            4 => '8.8折券',
            5 => '8.5折券',
            6 => '8折券',
            7 => '月运7折券',
            8 => '年运7.7折券',
            9 => '生时校正7折券',
            10 => '幸运之城7.7折券',
            11 => '婚姻报告7.7折券',
            12 => '财富报告7.7折券',
            13 => '事业报告7.7折券',
            14 => '学业报告7折券',
            15 => '日运免费券',
            16 => '月运免费券',
            17 => '年运免费券',
            18 => '事业报告免费券',
            19 => '学业报告免费券',
        ];

        $records = $prizeRecordModel->where(['active_id' => $this->activeId, 'prize_type' => 1])->group('prize_id')->column('count(prize_id)', 'prize_id');
        print_r("\r\n普通抽奖结果统计\r\n");
        foreach ($prizeNameConfig as $prizeId => $prizeName)
        {
            $prizeNum = $records[$prizeId] ?? 0;
            printf("%s\t------中奖次数：%d \t实际中奖概率：%.4f%% \n", $prizeName, $prizeNum, ($prizeNum > 0 ? $prizeNum / $userDatas['prize_lucky_num'] * 100 : 0));
        }

        print_r("\r\n潜力值抽奖结果统计\r\n");
        $prizeNameConfig2 = [
            15 => '日运免费券',
            16 => '月运免费券',
        ];
        $records1 = $prizeRecordModel->where(['active_id' => $this->activeId, 'prize_type' => 2])->group('prize_id')->column('count(prize_id)', 'prize_id');
        foreach ($prizeNameConfig2 as $prizeId => $prizeName)
        {
            $prizeNum = $records1[$prizeId] ?? 0;
            printf("%s\t------中奖次数：%d \n", $prizeName, $prizeNum);
        }

        print_r("\r\n普通抽奖次数统计\r\n");
        $prizeData0 = $prizeUserInfoModel->where('active_id', $this->activeId)->group('prize_lucky_num')->column('count(prize_lucky_num)', 'prize_lucky_num');
        foreach ($prizeData0 as $prize_lucky_num => $num)
        {
            printf("普通抽奖%d次\t------人数：%d \n", $prize_lucky_num, $num);
        }
        print_r("\r\n潜力值抽奖次数统计\r\n");
        $prizeData = $prizeUserInfoModel->where('active_id', $this->activeId)->group('senior_peize_num')->column('count(senior_peize_num)', 'senior_peize_num');
        foreach ($prizeData as $senior_peize_num => $num)
        {
            printf("潜力值抽奖%d次\t------人数：%d \n", $senior_peize_num, $num);
        }

        print_r("\r\n活动任务完成次数统计\r\n");
        $prizeNumIncRecordModel = new ZlActivePrizeNumIncRecord();

        $prizeNumRecordData = $prizeNumIncRecordModel->where('active_id', $this->activeId)->group('task_id')->column('task_name,count(task_id) num,sum(inc) total_inc', 'task_id');

        foreach ($prizeNumRecordData as $taskId => $taskInfo)
        {
            printf("%s\t -------->完成次数：%d\t 增加抽奖次数：%d \n", $taskInfo['task_name'], $taskInfo['num'], $taskInfo['total_inc']);
        }
        print_r("\r\n购买日运任务统计\r\n");
        $sql = Db::table('wechat_backup_07_18_14_43_00.zl_active_prize_num_inc_record')->where(['active_id' => $this->activeId, 'task_id' => 6])->group('uid')->field('sum(inc) total_inc')->buildSql();
        $resData = Db::table($sql . 'a')->group('a.total_inc')->column('count(a.total_inc)', 'a.total_inc');
        foreach ($resData as $total_inc => $people)
        {
            printf("购买日运-------->增加抽奖次数：%d\t --->人数：%d \n", $total_inc, $people);
        }
        print_r("\r\n购买月运任务统计\r\n");
        $sql = Db::table('wechat_backup_07_18_14_43_00.zl_active_prize_num_inc_record')->where(['active_id' => $this->activeId, 'task_id' => 7])->group('uid')->field('sum(inc) total_inc')->buildSql();
        $resData = Db::table($sql . 'a')->group('a.total_inc')->column('count(a.total_inc)', 'a.total_inc');
        foreach ($resData as $total_inc => $people)
        {
            printf("购买月运-------->增加抽奖次数：%d\t --->人数：%d \n", $total_inc, $people);
        }

        print_r("\r\n购买年运任务统计\r\n");
        $sql = Db::table('wechat_backup_07_18_14_43_00.zl_active_prize_num_inc_record')->where(['active_id' => $this->activeId, 'task_id' => 8])->group('uid')->field('sum(inc) total_inc')->buildSql();
        $resData = Db::table($sql . 'a')->group('a.total_inc')->column('count(a.total_inc)', 'a.total_inc');
        foreach ($resData as $total_inc => $people)
        {
            printf("购买年运-------->增加抽奖次数：%d\t --->人数：%d \n", $total_inc, $people);
        }
    }
}
